package org.yelongframework.spring.boot.context.config;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.yelongframework.util.Assert;

/**
 * 默认实现
 * 
 * @since 1.0.0
 */
public class DefaultConfigFileSearchLocationSupplier implements ConfigFileSearchLocationSupplier {

	/** 类加载器 */
	private final ClassLoader classLoader;

	// ==================================================constructor==================================================

	public DefaultConfigFileSearchLocationSupplier() {
		this(Thread.currentThread().getContextClassLoader());
	}

	/**
	 * @param classLoader 类加载器
	 */
	public DefaultConfigFileSearchLocationSupplier(ClassLoader classLoader) {
		Assert.notNull(classLoader, "classLoader cannot be null");
		this.classLoader = classLoader;
	}

	// ==================================================获取配置文件检索地址==================================================

	@Override
	public String getSearchLocations(String resourceName) {
		try {
			List<String> configDirList = resolveResource(resourceName);
			if (CollectionUtils.isEmpty(configDirList)) {
				return null;
			}
			List<String> configNameList = new ArrayList<>(configDirList.size() * 2);
			configDirList.forEach(x -> {
				configNameList.add("classpath:/" + resourceName + "/" + x + "/");
				configNameList.add("file:/" + resourceName + "/" + x + "/");
			});
			return configNameList.stream().collect(Collectors.joining(","));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	// ==================================================构建==================================================

	protected List<String> resolveResource(String resourceName) throws IOException {
		Enumeration<URL> resources = classLoader.getResources(resourceName);
		List<String> configDirList = new ArrayList<>();
		while (resources.hasMoreElements()) {
			URL url = resources.nextElement();
			if (url.getProtocol() == "jar") {
				JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
				JarFile jarFile = jarURLConnection.getJarFile();
				Enumeration<JarEntry> entries = jarFile.entries();
				while (entries.hasMoreElements()) {
					JarEntry jarEntry = entries.nextElement();
					if (!jarEntry.isDirectory()) {
						continue;
					}
					String jarEntryName = jarEntry.getName();
					if (jarEntryName.startsWith(resourceName)) {
						configDirList.add(jarEntryName);
					}
				}
			} else if (url.getProtocol() == "file") {
				File file = new File(url.getFile());
				List<String> fileDirAll = readFileDirAll(file);
				for (String fileDir : fileDirAll) {
					configDirList.add(fileDir.substring(file.getAbsolutePath().length() + 1).replace("\\", "/"));
				}
			} else {
				continue;
			}
		}
		return configDirList;
	}

	private List<String> readFileDirAll(File file) {
		List<String> fileDirList = new ArrayList<>();
		File[] listFiles = file.listFiles();
		for (File listFile : listFiles) {
			if (listFile.isDirectory()) {
				fileDirList.add(listFile.getAbsolutePath());
				fileDirList.addAll(readFileDirAll(listFile));
			}
		}
		return fileDirList;
	}

}
